#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "compiler.h"
#include "parser.h"

int trim_tail(char* str)
{
	char* end = str + strlen(str) ;
	while(*--end == ' ') *end = 0;
	return 0;
}

int scan_literal(char* str, char* out)
{
	char* p = str;
	char* t = out;
	char* l = p;
	while(*p)
	{
		l = p;
		if(*p == '{')
		{
			p++;
			while(*p && *p == ' ')p++;
			if(strncmp(p, "/literal", 8) == 0) 
			{
				p+=8;
				while(*p && *p == ' ')p++;
				
				if(*p == '}')
				{
					p++;
					l = p;
					break;
				}
			}
		}
		if(l < p)
		{
			memcpy(t, l, p - l);
			t+=p-l;
		}
		*t = *p;
		p++;
		t++;
	}
	*t = '\0';
	return p - str;

}

int scan_quote_string(char*str, char* out, char quote_type)
{
	int len;
	char* s, *t;
	s = str;
	t = out;
	while (*s && *s!=quote_type) 
	{
		if (*s=='\\') {
			s++;
			if (!s) {
				*t++ = '\\';
				break;
			}
			switch(*s) {
				case 'n':
					*t++ = '\n';
					break;
				case 'r':
					*t++ = '\r';
					break;
				case 't':
					*t++ = '\t';
					break;
				case 'f':
					*t++ = '\f';
					break;
				case 'v':
					*t++ = '\v';
					break;
				case 'e':
					*t++ = '\e';
					break;
				case '"':
				case '\'':
					if (*s != quote_type) {
						*t++ = '\\';
						*t++ = *s;
						break;
					}
				default:
					break;
			}
		} else {
			*t++ = *s;
		}
	
		s++;
	}
	*t = 0;
	return s - str + 1;
}

int get_next_token(lexer* l, token* yyvalue)
{
	
	char *m;
	char* yycursor = l->cursor;
	char* yymarker;
	char* yytext = l->cursor;
	int yyleng;
	if(l->cursor >= l->buf + l->len) return 0;
/*!re2c
	re2c:define:YYCTYPE  = "unsigned char";
	re2c:variable:yych   = curr;
	re2c:indent:top      = 2;
	re2c:yyfill:enable   = 0;
	re2c:yych:conversion = 1;
	re2c:labelprefix     = scan;

	comment="{*";
	open_tag = "{";
	close_tag = "}";
	integer = [0-9]+;
	dnum = ([0-9]*"."[0-9]+)|([0-9]+"."[0-9]*);
	hex =  "0"[xX][0-9a-fA-F]+;
	label = [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*;
	whitespace = [ \t];
	any_char = [^];
	newline = ("\r"|"\n"|"\r\n");

	<!*> { yyleng = YYCURSOR - (yytext); l->cursor = YYCURSOR;}
	<INITIAL>comment
	{
		while(*YYCURSOR)
		{
			if(*YYCURSOR =='*' && *(YYCURSOR+1) == '}')
			{	
				YYCURSOR++;
				YYCURSOR++;
				yyleng = YYCURSOR - (yytext); 
				l->cursor = YYCURSOR;
				yyvalue->type = T_COMMENT; 
				return 1;
			}
			YYCURSOR++;
		}
		fprintf(stderr, "Comment syntax error\n");
		return 0; 
	}
	<SMARTY>integer whitespace*  
	{
		char abuf[32];
		yyvalue->type = T_INTEGER;
		memcpy(abuf, yytext, yyleng);
		abuf[yyleng] = 0;
		ivalue(yyvalue->val) = atoi(abuf); 
		return 1;
	}
	<SMARTY>dnum whitespace*
	{
		char abuf[64];
		yyvalue->type = T_FLOAT;
		memcpy(abuf, yytext, yyleng);
		abuf[yyleng] = 0;
		fvalue(yyvalue->val) = atof(abuf); 
		return 1;
	}
	<SMARTY>hex whitespace* 
	{
		char abuf[32];
		char *p;
		yyvalue->type = T_INTEGER;
		memcpy(abuf, yytext, yyleng);
		abuf[yyleng] = 0;
		ivalue(yyvalue->val) = strtol(abuf, &p, 16); 
		return 1;
	}
	
	<SMARTY>"foreach" whitespace+
	{
		yyvalue->type = T_FOREACH;
		return 1;
	}
	<SMARTY>"as" whitespace+
	{
		yyvalue->type = T_AS;
		return 1;
	}
	
	<SMARTY>"=>" whitespace*
	{
		yyvalue->type = T_DOUBLE_ARROW;
		return 1;
	}

	<SMARTY>"/foreach" whitespace*
	{
		yyvalue->type = T_EFOREACH;
		return 1;
	}
	<SMARTY>"if" whitespace+
	{
		yyvalue->type = T_IF;
		return 1;
	}
	
	<SMARTY>"/if" whitespace*
	{
		yyvalue->type = T_EIF;
		return 1;
	}
	
	<SMARTY>"for" whitespace+
	{
		yyvalue->type=T_FOR; 
		return 1;
	}

	<SMARTY>"from" whitespace+
	{
		yyvalue->type=T_FROM; 
		return 1;
	}

	<SMARTY>"to" whitespace+
	{
		yyvalue->type=T_TO; 
		return 1;
	}

	<SMARTY>"/for" whitespace*
	{
		yyvalue->type=T_EFOR; 
		return 1;
	}
	
	<SMARTY>"("whitespace*{ yyvalue->type=T_OPENP; return 1;}
	<SMARTY>")"whitespace*{ yyvalue->type=T_CLOSEP; return 1;}
	<SMARTY>"["whitespace*{ yyvalue->type=T_OPENB; return 1;}
	<SMARTY>"]"whitespace*{ yyvalue->type=T_CLOSEB; return 1;}
	<SMARTY>"+"whitespace*{ yyvalue->type=T_PLUS; return 1;}
	<SMARTY>"-"whitespace*{ yyvalue->type=T_MINUS; return 1;}
	<SMARTY>"*"whitespace*{ yyvalue->type=T_TIMES; return 1;}
	<SMARTY>"/"whitespace*{ yyvalue->type=T_DIVIDE; return 1;}
	
	<SMARTY>","whitespace*{ yyvalue->type=T_COMMA; return 1;}
	<SMARTY>"."whitespace*{ yyvalue->type=T_DOT; return 1;}
	<SMARTY>"="whitespace*{ yyvalue->type=T_ASSIGN; return 1;}
	
	<SMARTY>"=="whitespace*{ yyvalue->type=T_EQ; return 1;}
	<SMARTY>"!="whitespace*{ yyvalue->type=T_NE; return 1;}
	<SMARTY>">" whitespace*{ yyvalue->type=T_GT; return 1;}
	<SMARTY>"<" whitespace*{ yyvalue->type=T_LT; return 1;}
	<SMARTY>">="whitespace*{ yyvalue->type=T_GE; return 1;}
	<SMARTY>"<="whitespace*{ yyvalue->type=T_LE; return 1;}
	<SMARTY>"&&"whitespace*{ yyvalue->type=T_AND; return 1;}
	<SMARTY>"||"whitespace*{ yyvalue->type=T_OR; return 1;}
	<SMARTY>"!"whitespace*{ yyvalue->type=T_NOT; return 1;}
	
	<SMARTY>"$"label whitespace*
	{
		yyvalue->type = T_VARIABLE;
		svalue(yyvalue->val) = strndup(yytext, yyleng);
		trim_tail(svalue(yyvalue->val));
		return 1;
	}
	
	<SMARTY>label whitespace*
	{
		yyvalue->type = T_LABEL;
		svalue(yyvalue->val) = strndup(yytext, yyleng);
		trim_tail(svalue(yyvalue->val));
		return 1;
	}

	<SMARTY>close_tag 
	{
		BEGIN(INITIAL);
		yyvalue->type=T_RDEL; 
		return 1;
	}
	<SMARTY>"\""
	{
		char double_quote_str[1024];
		YYCURSOR += scan_quote_string(YYCURSOR,double_quote_str,  '\"');
		l->cursor = YYCURSOR;
		yyvalue->type = T_DSTRING;
		svalue(yyvalue->val) = strdup(double_quote_str);	
		return 1; 
	}
	<SMARTY>"'"
	{
		char single_quote_str[1024];
		YYCURSOR += scan_quote_string(YYCURSOR,single_quote_str,  '\'');
		l->cursor = YYCURSOR;
		yyvalue->type = T_DSTRING;
		svalue(yyvalue->val) = strdup(single_quote_str);
		return 1; 
	}
	<SMARTY>"literal" whitespace* close_tag
	{
		char literal_str[1024]={0};	
		YYCURSOR += scan_literal(YYCURSOR,literal_str);
		l->cursor = YYCURSOR;
		yyvalue->type = T_INNER_HTML;
		svalue(yyvalue->val) = strdup(literal_str);
		BEGIN(INITIAL);
		return 1; 
	}
	<INITIAL>open_tag whitespace*
	{
		BEGIN(SMARTY);
		yyvalue->type = T_LDEL;  
		return 1;
	}
	
	<INITIAL>any_char
	{		
		while(*YYCURSOR)
		{
			if(*YYCURSOR =='{')
			{	
				break;
			}
			YYCURSOR++;
		}
		yyleng = YYCURSOR - (yytext); 
		l->cursor = YYCURSOR;
		yyvalue->type = T_INNER_HTML; 
		svalue(yyvalue->val) = strndup(yytext, yyleng);
		return 1;
	}
*/

}

